package jrain.fw.dao.common.parser;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import jrain.fw.core.consts.Consts;
import jrain.fw.core.dao.bean.SqlBean;
import jrain.fw.dao.common.parser.bean.ConditionBean;
import jrain.fw.dao.common.parser.bean.IfExpression;
import jrain.fw.dao.common.parser.bean.ParseBean;
import jrain.fw.dao.common.parser.bean.RootExpression;
import jrain.fw.dao.common.parser.bean.SubSqlExpression;
import jrain.fw.dao.common.parser.bean.VarExpression;
import jrain.utils.ch.CharUtils;
import jrain.utils.collection.CollectionUtils;
import jrain.utils.consts.BaseConst;
import jrain.utils.exception.ServiceException;
import jrain.utils.lang.LangUtils;
import jrain.utils.lang.StringUtils;

public class BaseSqlParser {

	private static final List<String> OP_LIST = new ArrayList<>();
	private static final char IF_PRE_START = 'i';
	private static final String IF_START = "if(";
	private static final String ELSE = "else";
	private static final String VAR_START = "#{";
	static {
		OP_LIST.add("==");
		OP_LIST.add("!=");
		OP_LIST.add("is");
		OP_LIST.add("isnot");
	}

	public SqlBean parseSql(Map<String, Object> sqlCfg, Map<String, Object> paramData) {
		String sql = StringUtils.trimNull(sqlCfg.get(Consts.CFG_SQL_VALUE));
		RootExpression rootExpression = parserSql(sql);
		Map<String, Object> ctx = new HashMap<>();
		SqlBean sqlBean = rootExpression.calcSql(sqlCfg, paramData, ctx);
		// 判定，update 和 remove
		String type = StringUtils.trimNull(sqlCfg.get(Consts.CFG_SQL_TYPE));
		if (Consts.CFG_SQL_TYPE_UPDATE.equals(type) || Consts.CFG_SQL_TYPE_DELETE.equals(type)) {
			int varCount = LangUtils.parseInt(ctx.get(Consts.SQL_CTX_COUNT_VAR));
			int varCodition = LangUtils.parseInt(ctx.get(Consts.SQL_CTX_COUNT_CONDITION));
			if (varCount == 0 && varCodition == 0) {
				throw new ServiceException("unconditional updates or deletes are not supported!");
			}
		}
		return sqlBean;
	}

	public RootExpression parserSql(String sql) {
		// 过滤需要的数据
		sql = filterInvalidChar(sql);
		RootExpression expression = new RootExpression();
		int sqlLength = sql.length();
		int preIndex = 0;
		for (int index = 0; index < sql.length(); index++) {
			String match = VAR_START;
			int tempIndex = index + 2;
			// 变量开始
			if (tempIndex <= sqlLength) {
				String tempChar = sql.substring(index, index + 2);
				if (match.equals(tempChar)) {
					// 基础SQL
					if (index > preIndex) {
						String subSql = sql.substring(preIndex, index);
						SubSqlExpression sqlExpression = new SubSqlExpression();
						sqlExpression.setSubSql(subSql);
						expression.addExpression(sqlExpression);
						preIndex = index;
					}
					ParseBean bean = parserVar(sql, index);
					index = bean.getIndex();
					preIndex = index;
					// 因为 for循环会自动加1
					index = index - 1;
					expression.addExpression(bean.getExpression());
					continue;
				}
			}
			// 搜索IF，格式:空格IF
			char ch = sql.charAt(index);
			if (CharUtils.isWhitespace(ch)) {
				match = IF_START;
				tempIndex = index + 4;
				if (tempIndex <= sqlLength) {
					String tempChar = sql.substring(index + 1, tempIndex);
					if (match.equals(tempChar)) {
						// 基础SQL
						if (index > preIndex) {
							String subSql = sql.substring(preIndex, index);
							SubSqlExpression sqlExpression = new SubSqlExpression();
							sqlExpression.setSubSql(subSql);
							expression.addExpression(sqlExpression);
							preIndex = index;
						}
						ParseBean bean = parserIf(sql, index + 1);
						index = bean.getIndex();
						preIndex = index;
						// 因为 for循环会自动加1
						index = index - 1;
						expression.addExpression(bean.getExpression());
						continue;
					}
				}
			}
			// 如果SQL直接以IF开始
			if (index == 0 && ch == IF_PRE_START) {
				if (sql.startsWith(IF_START)) {
					ParseBean bean = parserIf(sql, 0);
					index = bean.getIndex();
					preIndex = index;
					// 因为 for循环会自动加1
					index = index - 1;
					expression.addExpression(bean.getExpression());
					continue;
				}
			}

		}
		if (sqlLength > preIndex) {
			String subSql = sql.substring(preIndex, sqlLength);
			SubSqlExpression sqlExpression = new SubSqlExpression();
			sqlExpression.setSubSql(subSql);
			expression.addExpression(sqlExpression);
		}
		return expression;
	}

	protected ParseBean parserVar(String sql, int index) {
		ParseBean parseBean = new ParseBean();
		int oldInIndex = index;
		index = index + 2;
		assertVarErrorLength(index < sql.length());
		String tempVar = sql.substring(oldInIndex, index);
		if (!VAR_START.equals(tempVar)) {
			paserVarError(tempVar);
		}
		StringBuilder sb = new StringBuilder();
		// 匹配更多字符
		while (index < sql.length()) {
			char ch = sql.charAt(index);
			if (ch == BaseConst.CRIGHT_HKH) {
				index++;
				break;
			} else {
				sb.append(ch);
				index++;
			}
		}
		// 可能是值变量结束SQL语句
		assertVarErrorLength(index <= sql.length());

		String var = sb.toString();
		if (var.length() == 0) {
			paserVarError(BaseConst.EMPTY);
		}
		// 跳过空白
		VarExpression varExpression = new VarExpression();
		varExpression.setVar(var);
		parseBean.setExpression(varExpression);
		parseBean.setIndex(index);
		return parseBean;
	}

	protected ParseBean parserIf(String sql, int index) {
		ParseBean parseBean = new ParseBean();
		int oldInIndex = index;
		index = index + 3;
		assertVarErrorLength(index < sql.length());
		String tempBean = sql.substring(oldInIndex, index);
		if (!IF_START.equals(tempBean)) {
			paserIfError(tempBean);
		}
		IfExpression ifExpression = new IfExpression();
		parseBean.setExpression(ifExpression);

		// 匹配条件开始============
		int pointAInex = index;
		int pointACounter = 0;
		char ch = BaseConst.CEMPTY_SPACE;
		while (index < sql.length()) {
			ch = sql.charAt(index);
			if (ch == BaseConst.CLEFT_XKH) {
				pointACounter++;

			} else if (ch == BaseConst.CRIGHT_XKH) {
				if (pointACounter == 0) {
					break;
				} else {
					pointACounter--;
				}
			}
			index++;
		}
		assertIfErrorLength(index < sql.length());
		String condition = sql.substring(pointAInex, index);
		if (ch == BaseConst.CRIGHT_XKH) {
			ifExpression.setCondition(parserConditon(condition));
		} else {
			paserIfError(condition);
		}
		index++;
		// 匹配条件结束============
		// 跳过空白
		index = skip(sql, index);
		assertIfErrorLength(index < sql.length());
		// 匹配IF内容开始============
		ch = sql.charAt(index++);
		assertIfErrorLength(ch == BaseConst.CLEFT_HKH);
		int pointBInext = index;
		int pointBCounter = 0;
		// 向后搜索到}
		while (index < sql.length()) {
			ch = sql.charAt(index);
			if (ch == BaseConst.CLEFT_HKH) {
				pointBCounter++;

			} else if (ch == BaseConst.CRIGHT_HKH) {
				if (pointBCounter == 0) {
					break;
				} else {
					pointBCounter--;
				}
			}
			index++;
		}
		String ifSubSql = sql.substring(pointBInext, index);
		if (ch == BaseConst.CRIGHT_HKH) {
			// 匹配SQL
			RootExpression rootExpression = parserSql(ifSubSql);
			ifExpression.setIfExpr(rootExpression);
		} else {
			paserIfError(ifSubSql);
		}
		index++;
		// 匹配IF内容结束============
		ParseBean elseBean = parserElse(sql, index);
		ifExpression.setElseExpr(elseBean.getExpression());
		parseBean.setIndex(elseBean.getIndex());
		return parseBean;
	}

	protected static ConditionBean parserConditon(String condition) {

		condition = StringUtils.trimNull(condition);
		if (condition.contains("==")) {
			List<String> list = CollectionUtils.valueOfList(condition, "==");
			if (list.size() == 2) {
				ConditionBean bean = new ConditionBean();
				bean.setValue1(list.get(0));
				bean.setOp("==");
				String value = list.get(1);
				if("null".equals(value)) {
					bean.setValue2(null);
				}else {
					bean.setValue2(value);
				}
				return bean;
			}
		} else if (condition.contains("!=")) {
			List<String> list = CollectionUtils.valueOfList(condition, "!=");
			if (list.size() == 2) {
				ConditionBean bean = new ConditionBean();
				bean.setValue1(list.get(0));
				bean.setOp("!=");
				String value = list.get(1);
				if("null".equals(value)) {
					bean.setValue2(null);
				}else {
					bean.setValue2(value);
				}
				return bean;
			}
		} else if (condition.contains(" is ")) {
			List<String> list = CollectionUtils.valueOfList(condition, " is ");
			if (list.size() == 2) {
				ConditionBean bean = new ConditionBean();
				bean.setValue1(list.get(0));
				bean.setOp("is");
				bean.setValue2(list.get(1));
				return bean;
			}
		} else if (condition.contains(" isnot ")) {
			List<String> list = CollectionUtils.valueOfList(condition, " isnot ");
			if (list.size() == 2) {
				ConditionBean bean = new ConditionBean();
				bean.setValue1(list.get(0));
				bean.setOp("isnot");
				bean.setValue2(list.get(1));
				return bean;
			}
		}
		throw new ServiceException("if expression condition parsing error! condition=" + condition);
	}

	
	protected ParseBean parserElse(String sql, int index) {
		index = skip(sql, index);
		ParseBean parseBean = new ParseBean();
		parseBean.setIndex(index);
		// 尝试搜索else
		if (index + 4 < sql.length() && ELSE.equals(sql.substring(index, index + 4))) {
			index = index + 4;
			int bindex = index;
			index = skip(sql, bindex);
			boolean bspace = index > bindex;
			assertIfErrorLength(index < sql.length());
			char ch = sql.charAt(index);
			// else 模块
			if (ch == BaseConst.CLEFT_HKH) {
				index++;
				int pointInex = index;
				int pointCounter = 0;
				// 向后搜索到}
				while (index < sql.length()) {
					ch = sql.charAt(index);
					if (ch == BaseConst.CLEFT_HKH) {
						pointCounter++;

					} else if (ch == BaseConst.CRIGHT_HKH) {
						if (pointCounter == 0) {
							break;
						} else {
							pointCounter--;
						}
					}
					index++;
				}

				String ifSubSql = sql.substring(pointInex, index);
				if (ch == BaseConst.CRIGHT_HKH) {
					// 匹配SQL
					RootExpression rootExpression = parserSql(ifSubSql);
					parseBean.setExpression(rootExpression);
				} else {
					paserIfError(ifSubSql);
				}
				index++;
				parseBean.setIndex(index);
			}
			// else if 模块
			else if (bspace && ch == 'i') {
				ParseBean tempBean = parserIf(sql, index);
				parseBean.setExpression(tempBean.getExpression());
				parseBean.setIndex(tempBean.getIndex());

			} else {
				paserIfError("Illegal else module");
			}
		}
		return parseBean;
	}

	protected int skip(String sql, int index) {
		while (index < sql.length()) {
			char ch = sql.charAt(index);
			if (CharUtils.isWhitespace(ch)) {
				index = index + 1;
			} else {
				break;
			}
		}
		return index;
	}

	// 过滤sql无效字符
	protected String filterInvalidChar(String sql) {
		StringBuilder sb = new StringBuilder();
		boolean lastWhitespace = false;
		int sqlLength = sql.length();
		for (int i = 0; i < sqlLength; i++) {
			char ch = sql.charAt(i);
			// 判定字符串
			if (ch == BaseConst.CSINGLE_QUOTATION) {
				// 向后搜索到换行
				sb.append(BaseConst.CSINGLE_QUOTATION);
				for (int j = i + 1; j < sqlLength; j++) {
					char ech = sql.charAt(j);
					if (ech == BaseConst.CSINGLE_QUOTATION) {
						i = j;
						break;
					} else {
						sb.append(ech);
					}
				}
			}
			// 单行注释
			if (ch == BaseConst.CZHX) {
				if (i + 1 < sql.length()) {
					char ch1 = sql.charAt(i + 1);
					// 单行注释确认
					if (ch1 == BaseConst.CZHX) {
						// 向后搜索到换行
						boolean bend = false;
						for (int j = i + 1; j < sqlLength; j++) {
							char ech = sql.charAt(j);
							if (ech == '\r' || ech == '\n') {
								i = j;
								bend = true;
								break;
							}
						}
						if (!lastWhitespace) {
							sb.append(BaseConst.EMPTY_SPACE);
						}
						lastWhitespace = true;
						if (bend) {
							continue;
						} else {
							break;
						}
					}
				}

			}
			// 多行注释
			if (ch == BaseConst.CDIVIDE) {
				if (i + 1 < sql.length()) {
					char ch1 = sql.charAt(i + 1);
					// 多行注释确认
					if (ch1 == BaseConst.CMULTI) {
						// 向后搜索到注释结尾
						boolean bend = false;
						for (int j = i + 1; j < sqlLength - 1; j++) {
							char ech = sql.charAt(j);
							char ech1 = sql.charAt(j + 1);
							if (ech == BaseConst.CMULTI && ech1 == BaseConst.CDIVIDE) {
								i = j + 1;
								bend = true;
								break;
							}
						}
						if (!lastWhitespace) {
							sb.append(BaseConst.EMPTY_SPACE);
						}
						lastWhitespace = true;
						if (bend) {
							continue;
						} else {
							break;
						}
					}
				}
			}
			// 空白字符
			if (CharUtils.isWhitespace(ch)) {
				if (!lastWhitespace) {
					sb.append(BaseConst.EMPTY_SPACE);
				}
				lastWhitespace = true;
			} else {
				sb.append(ch);
				lastWhitespace = false;
			}
		}
		return sb.toString();
	}

	protected void paserVarError(String msg) {
		throw new ServiceException("variable expression parsing error! msg=" + msg);
	}

	protected void assertVarErrorLength(boolean b) {
		if (!b) {
			throw new ServiceException("variable expression parsing error!");
		}
	}

	protected void paserIfError(String msg) {
		throw new ServiceException("if expression parsing error! msg=" + msg);
	}

	protected void assertIfErrorLength(boolean b) {
		if (!b) {
			throw new ServiceException("if expression parsing error!");
		}
	}
	
}
